package com.xiaobias.a39;

import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;

import java.lang.reflect.Constructor;
import java.util.List;

public class A39_2 {
    public static void main(String[] args) throws Exception {
        // 添加 app 监听器
        SpringApplication app = new SpringApplication();
        app.addListeners(event -> System.out.println(event.getClass()));

        // 获取事件发送器实现类名
        List<String> names = SpringFactoriesLoader.loadFactoryNames(SpringApplicationRunListener.class, A39_2.class.getClassLoader());
        for (String name : names) {
            System.out.println(name);
            Class<?> clazz = Class.forName(name);
            Constructor<?> constructor = clazz.getConstructor(SpringApplication.class, String[].class);
            SpringApplicationRunListener publisher = (SpringApplicationRunListener) constructor.newInstance(app, args);

            // 发布事件
            DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
            GenericApplicationContext context = new GenericApplicationContext();
            StandardEnvironment environment = new StandardEnvironment();
            // 1. spring boot 开始启动
            publisher.starting(bootstrapContext);
            // 2. 环境变量准备完毕
            publisher.environmentPrepared(bootstrapContext, environment);
            // 3. 在 spring 容器创建，并调用初始化器之后，发送此事件
            publisher.contextPrepared(context);
            // 4. 所有 bean definition 加载完毕
            publisher.contextLoaded(context);
            // 5. spring 容器初始化完毕（refresh 方法调用完毕）
            context.refresh();
            publisher.started(context);
            // 6. spring boot 启动完毕
            publisher.running(context);
            // 7. spring boot 启动出错
            publisher.failed(context, new RuntimeException("出错了"));
        }
    }
}
